package ink.mint.loss;

import ink.mint.activation.Activateable;
import ink.mint.activation.ActivationFunction;
import ink.mint.matrix.Matrix;
import ink.mint.matrix.Matrixable;
import ink.mint.neural.Layer;

import java.io.Serializable;

public class LossFunction implements Lossable, Serializable {
    /**
     * 网络层
     */
    Layer layer;

    /**
     * 损失函数类型
     */
    LossType lossType;
    /**
     * 矩阵
     */
    Matrixable matrix;
    /**
     * 激活函数
     */
    Activateable activateable;

    double huBerLossFunctionDelta = 0;
    double focalLossFunctionAlpha;
    double focalLossFunctionBeta;
    /**
     * 损失函数的构造器
     *
     * @param lossType 损失类型
     */
    public LossFunction(LossType lossType) {
        this.lossType = lossType;
        this.matrix = new Matrix();
        this.activateable = new ActivationFunction();
    }

    /**
     * 无参数的损失函数构造器
     */
    public LossFunction() {
        this.matrix = new Matrix();
        this.activateable = new ActivationFunction();
    }

    /**
     * 设置网络层
     *
     * @param layer 网络层
     * @return 损失函数
     */
    public LossFunction setLayer(Layer layer) {
        this.layer = layer;
        return this;
    }

    /**
     * 损失函数的解
     *
     * @param expectations 期望
     * @param output       输出
     * @param lossType     损失函数类型:Huber损失函数
     * @param delta        Huber损失函数的delta超参数
     * @return huber损失函数的解
     */
    public double LossSolve(double expectations, double output, LossType lossType, double delta) {
        if (delta == 0) {
            System.out.println("超参数delta需要赋值");
        }
        switch (lossType) {
            case HuBerLossFunction:
                return huBerLossFunction(expectations, output, delta);
            default:
                return 0;
        }
    }

    /**
     * 损失函数的解
     *
     * @param expectations 期望
     * @param output       输出
     * @param lossType     损失函数类型:Huber损失函数
     * @param delta        Huber损失函数的delta超参数
     * @return huber损失函数的解
     */
    public double LossSolve(double[] expectations, double[] output, LossType lossType, double delta) {
        if (delta == 0) {
            System.out.println("超参数delta需要赋值");
        }
        switch (lossType) {
            case HuBerLossFunction:
                return huBerLossFunction(expectations, output, delta);
            default:
                return 0;
        }
    }

    /**
     * 损失函数的解
     *
     * @param expectations 期望
     * @param output       输出
     * @param lossType     损失函数类型:Huber损失函数
     * @param delta        Huber损失函数的delta超参数
     * @return huber损失函数的解
     */
    public double LossSolve(double[][] expectations, double[][] output, LossType lossType, double delta) {
        if (delta == 0) {
            System.out.println("超参数delta需要赋值");
        }
        switch (lossType) {
            case HuBerLossFunction:
                return huBerLossFunction(expectations, output, delta);
            default:
                return 0;
        }
    }

    /**
     * 损失函数的解
     *
     * @param expectations 期望
     * @param output       输出
     * @param lossType     损失函数类型:Focal损失函数
     * @param alpha        Focal损失函数的alpha超参数
     * @param beta         Focal损失函数的beta超参数
     * @return Focal损失函数的解
     */
    public double LossSolve(double expectations, double output, LossType lossType, double alpha, double beta) {
        if (alpha == 0 || beta == 0) {
            System.out.println("超参数alpha和超参数beta需要赋值");
        }
        switch (lossType) {
            case FocalLossFunction:
                return focalLossFunction(expectations, output, alpha, beta);
            default:
                return 0;
        }
    }

    /**
     * 损失函数的解
     *
     * @param expectations 期望
     * @param output       输出
     * @param lossType     损失函数类型:Focal损失函数
     * @param alpha        Focal损失函数的alpha超参数
     * @param beta         Focal损失函数的beta超参数
     * @return Focal损失函数的解
     */
    public double LossSolve(double[] expectations, double[] output, LossType lossType, double alpha, double beta) {
        if (alpha == 0 || beta == 0) {
            System.out.println("超参数alpha和超参数beta需要赋值");
        }
        switch (lossType) {
            case FocalLossFunction:
                return focalLossFunction(expectations, output, alpha, beta);
            default:
                return 0;
        }
    }

    /**
     * 损失函数的解
     *
     * @param expectations 期望
     * @param output       输出
     * @param lossType     损失函数类型:Focal损失函数
     * @param alpha        Focal损失函数的alpha超参数
     * @param beta         Focal损失函数的beta超参数
     * @return Focal损失函数的解
     */
    public double LossSolve(double[][] expectations, double[][] output, LossType lossType, double alpha, double beta) {
        if (alpha == 0 || beta == 0) {
            System.out.println("超参数alpha和超参数beta需要赋值");
        }
        switch (lossType) {
            case FocalLossFunction:
                return focalLossFunction(expectations, output, alpha, beta);
            default:
                return 0;
        }
    }

    /**
     * 损失函数的解
     *
     * @param expectations 期望
     * @param output       输出
     * @param lossType     损失函数类型:均方误差损失函数（MSE）、L2损失函数、L1损失函数、Smooth L1损失函数、KL散度函数（相对熵）、交叉熵损失、softmax损失函数
     * @return 损失函数的解
     */
    public double LossSolve(double expectations, double output, LossType lossType) {
        switch (lossType) {
            case MeanSquareErrorLossFunction:
                return meanSquareErrorLossFunction(expectations, output);
            case L2LossFunction:
                return l2LossFunction(expectations, output);
            case L1LossFunction:
                return l1LossFunction(expectations, output);
            case SmoothL1LossFunction:
                return smoothL1LossFunction(expectations, output);
            case KullbackLeiblerDivergenceFunction:
                return kullbackLeiblerDivergenceFunction(expectations, output);
            case CrossEntropyLossFunction:
                return crossEntropyLossFunction(expectations, output);
            case SoftmaxLossFunction:
                return softmaxLossFunction(expectations, output);
            default:
                return 0;
        }
    }

    /**
     * 损失函数的解
     *
     * @param expectations 期望
     * @param output       输出
     * @param lossType     损失函数类型:均方误差损失函数（MSE）、L2损失函数、L1损失函数、Smooth L1损失函数、KL散度函数（相对熵）、交叉熵损失、softmax损失函数
     * @return 损失函数的解
     */
    public double LossSolve(double[] expectations, double[] output, LossType lossType) {
        switch (lossType) {
            case MeanSquareErrorLossFunction:
                return meanSquareErrorLossFunction(expectations, output);
            case L2LossFunction:
                return l2LossFunction(expectations, output);
            case L1LossFunction:
                return l1LossFunction(expectations, output);
            case SmoothL1LossFunction:
                return smoothL1LossFunction(expectations, output);
            case KullbackLeiblerDivergenceFunction:
                return kullbackLeiblerDivergenceFunction(expectations, output);
            case CrossEntropyLossFunction:
                return crossEntropyLossFunction(expectations, output);
            case SoftmaxLossFunction:
                return softmaxLossFunction(expectations, output);
            default:
                return 0;
        }
    }

    /**
     * 损失函数的解
     *
     * @param expectations 期望
     * @param output       输出
     * @param lossType     损失函数类型:均方误差损失函数（MSE）、L2损失函数、L1损失函数、Smooth L1损失函数、KL散度函数（相对熵）、交叉熵损失、softmax损失函数
     * @return 损失函数的解
     */
    public double LossSolve(double[][] expectations, double[][] output, LossType lossType) {
        switch (lossType) {
            case MeanSquareErrorLossFunction:
                return meanSquareErrorLossFunction(expectations, output);
            case L2LossFunction:
                return l2LossFunction(expectations, output);
            case L1LossFunction:
                return l1LossFunction(expectations, output);
            case SmoothL1LossFunction:
                return smoothL1LossFunction(expectations, output);
            case KullbackLeiblerDivergenceFunction:
                return kullbackLeiblerDivergenceFunction(expectations, output);
            case CrossEntropyLossFunction:
                return crossEntropyLossFunction(expectations, output);
            case SoftmaxLossFunction:
                return softmaxLossFunction(expectations, output);
            default:
                return 0;
        }
    }


    /**
     * 损失函数求导的解
     *
     * @param expectations 期望
     * @param output       输出
     * @param lossType     损失函数类型:Huber损失函数
     * @param delta        Huber损失函数的delta超参数
     * @return huber损失函数求导的解
     */
    public double derivationLossSolve(double expectations, double output, LossType lossType, double delta) {
        if (delta == 0) {
            System.out.println("超参数delta需要赋值");
        }
        switch (lossType) {
            case HuBerLossFunction:
                return derivationHuBerLossFunction(expectations, output);
            default:
                return 0;
        }
    }

    /**
     * 损失函数求导的解
     *
     * @param expectations 期望
     * @param output       输出
     * @param lossType     损失函数类型:Huber损失函数
     * @param delta        Huber损失函数的delta超参数
     * @return huber损失函数求导的解
     */
    public double[] derivationLossSolve(double[] expectations, double[] output, LossType lossType, double delta) {
        if (delta == 0) {
            System.out.println("超参数delta需要赋值");
        }
        switch (lossType) {
            case HuBerLossFunction:
                return derivationHuBerLossFunction(expectations, output);
            default:
                return new double[0];
        }
    }

    /**
     * 损失函数求导的解
     *
     * @param expectations 期望
     * @param output       输出
     * @param lossType     损失函数类型:Huber损失函数
     * @param delta        Huber损失函数的delta超参数
     * @return huber损失函数求导的解
     */
    public double[][] derivationLossSolve(double[][] expectations, double[][] output, LossType lossType, double delta) {
        if (delta == 0) {
            System.out.println("超参数delta需要赋值");
        }
        switch (lossType) {
            case HuBerLossFunction:
                return derivationHuBerLossFunction(expectations, output);
            default:
                return new double[0][];
        }
    }

    /**
     * 损失函数求导的解
     *
     * @param expectations 期望
     * @param output       输出
     * @param lossType     损失函数类型:Focal损失函数
     * @param alpha        Focal损失函数的alpha超参数
     * @param beta         Focal损失函数的beta超参数
     * @return Focal损失函数求导的解
     */
    public double derivationLossSolve(double expectations, double output, LossType lossType, double alpha, double beta) {
        if (alpha == 0 || beta == 0) {
            System.out.println("超参数alpha和超参数beta需要赋值");
        }
        switch (lossType) {
            case FocalLossFunction:
                return derivationFocalLossFunction(expectations, output);
            default:
                return 0;
        }
    }

    /**
     * 损失函数求导的解
     *
     * @param expectations 期望
     * @param output       输出
     * @param lossType     损失函数类型:Focal损失函数
     * @param alpha        Focal损失函数的alpha超参数
     * @param beta         Focal损失函数的beta超参数
     * @return Focal损失函数求导的解
     */
    public double[] derivationLossSolve(double[] expectations, double[] output, LossType lossType, double alpha, double beta) {
        if (alpha == 0 || beta == 0) {
            System.out.println("超参数alpha和超参数beta需要赋值");
        }
        switch (lossType) {
            case FocalLossFunction:
                return derivationFocalLossFunction(expectations, output);
            default:
                return new double[0];
        }
    }

    /**
     * 损失函数求导的解
     *
     * @param expectations 期望
     * @param output       输出
     * @param lossType     损失函数类型:Focal损失函数
     * @param alpha        Focal损失函数的alpha超参数
     * @param beta         Focal损失函数的beta超参数
     * @return Focal损失函数求导的解
     */
    public double[][] derivationLossSolve(double[][] expectations, double[][] output, LossType lossType, double alpha, double beta) {
        if (alpha == 0 || beta == 0) {
            System.out.println("超参数alpha和超参数beta需要赋值");
        }
        switch (lossType) {
            case FocalLossFunction:
                return derivationFocalLossFunction(expectations, output);
            default:
                return new double[0][];
        }
    }

    /**
     * 损失函数求导的解
     *
     * @param expectations 期望
     * @param output       输出
     * @param lossType     损失函数类型:均方误差损失函数（MSE）、L2损失函数、L1损失函数、Smooth L1损失函数、KL散度函数（相对熵）、交叉熵损失、softmax损失函数
     * @return 损失函数求导的解
     */
    public double derivationLossSolve(double expectations, double output, LossType lossType) {
        switch (lossType) {
            case MeanSquareErrorLossFunction:
                return derivationMeanSquareErrorLossFunction(expectations, output);
            case L2LossFunction:
                return derivationL2LossFunction(expectations, output);
            case L1LossFunction:
                return derivationL1LossFunction(expectations, output);
            case SmoothL1LossFunction:
                return derivationSmoothL1LossFunction(expectations, output);
            case KullbackLeiblerDivergenceFunction:
                return derivationKullbackLeiblerDivergenceFunction(expectations, output);
            case CrossEntropyLossFunction:
                return derivationCrossEntropyLossFunction(expectations, output);
            case SoftmaxLossFunction:
                return derivationSoftmaxLossFunction(expectations, output);
            default:
                return 0;
        }
    }

    /**
     * 损失函数求导的解
     *
     * @param expectations 期望
     * @param output       输出
     * @param lossType     损失函数类型:均方误差损失函数（MSE）、L2损失函数、L1损失函数、Smooth L1损失函数、KL散度函数（相对熵）、交叉熵损失、softmax损失函数
     * @return 损失函数求导的解
     */
    public double[] derivationLossSolve(double[] expectations, double[] output, LossType lossType) {
        switch (lossType) {
            case MeanSquareErrorLossFunction:
                return derivationMeanSquareErrorLossFunction(expectations, output);
            case L2LossFunction:
                return derivationL2LossFunction(expectations, output);
            case L1LossFunction:
                return derivationL1LossFunction(expectations, output);
            case SmoothL1LossFunction:
                return derivationSmoothL1LossFunction(expectations, output);
            case KullbackLeiblerDivergenceFunction:
                return derivationKullbackLeiblerDivergenceFunction(expectations, output);
            case CrossEntropyLossFunction:
                return derivationCrossEntropyLossFunction(expectations, output);
            case SoftmaxLossFunction:
                return derivationSoftmaxLossFunction(expectations, output);
            default:
                return new double[0];
        }
    }

    /**
     * 损失函数求导的解
     *
     * @param expectations 期望
     * @param output       输出
     * @param lossType     损失函数类型:均方误差损失函数（MSE）、L2损失函数、L1损失函数、Smooth L1损失函数、KL散度函数（相对熵）、交叉熵损失、softmax损失函数
     * @return 损失函数求导的解
     */
    public double[][] derivationLossSolve(double[][] expectations, double[][] output, LossType lossType) {
        switch (lossType) {
            case MeanSquareErrorLossFunction:
                return derivationMeanSquareErrorLossFunction(expectations, output);
            case L2LossFunction:
                return derivationL2LossFunction(expectations, output);
            case L1LossFunction:
                return derivationL1LossFunction(expectations, output);
            case SmoothL1LossFunction:
                return derivationSmoothL1LossFunction(expectations, output);
            case KullbackLeiblerDivergenceFunction:
                return derivationKullbackLeiblerDivergenceFunction(expectations, output);
            case CrossEntropyLossFunction:
                return derivationCrossEntropyLossFunction(expectations, output);
            case SoftmaxLossFunction:
                return derivationSoftmaxLossFunction(expectations, output);
            default:
                return new double[0][];
        }
    }


    /**
     * 均方误差损失函数（MSE）
     *
     * @param expectations 期望值（标量）
     * @param output       输出值（标量）
     * @return 均方误差损失函数（MSE）的解（标量）
     */
    @Override
    public double meanSquareErrorLossFunction(double expectations, double output) {
        return Math.pow(output - expectations, 2);
    }

    /**
     * 均方误差损失函数（MSE）
     *
     * @param expectations 期望值（向量）
     * @param output       输出值（向量）
     * @return 均方误差损失函数（MSE）的解（标量）
     */
    @Override
    public double meanSquareErrorLossFunction(double[] expectations, double[] output) {
        int er = expectations.length;
        double[] square = matrix.pow(matrix.sub(output, expectations), 2);
        return matrix.vectorSum(square) / er;
    }

    /**
     * 均方误差损失函数（MSE）
     *
     * @param expectations 期望值（矩阵）
     * @param output       输出值（矩阵）
     * @return 均方误差损失函数（MSE）的解（标量）
     */
    @Override
    public double meanSquareErrorLossFunction(double[][] expectations, double[][] output) {
        int er = expectations.length;
        int ec = expectations[0].length;
        double[][] square = matrix.pow(matrix.sub(output, expectations), 2);
        return matrix.matrixSum(square) / (er * ec);
    }

    /**
     * L2损失函数
     *
     * @param expectations 期望值（标量）
     * @param output       输出值（标量）
     * @return L2损失函数的解（标量）
     */
    @Override
    public double l2LossFunction(double expectations, double output) {
        return Math.sqrt(Math.pow(output - expectations, 2));
    }

    /**
     * L2损失函数
     *
     * @param expectations 期望值（向量）
     * @param output       输出值（向量）
     * @return L2损失函数的解（标量）
     */
    @Override
    public double l2LossFunction(double[] expectations, double[] output) {
        int er = expectations.length;
        double[] square = matrix.pow(matrix.sub(output, expectations), 2);
        double result = matrix.vectorSum(square) / er;
        return Math.sqrt(result);
    }

    /**
     * L2损失函数
     *
     * @param expectations 期望值（矩阵）
     * @param output       输出值（矩阵）
     * @return L2损失函数的解（标量）
     */
    @Override
    public double l2LossFunction(double[][] expectations, double[][] output) {
        int er = expectations.length;
        int ec = expectations[0].length;
        double[][] square = matrix.pow(matrix.sub(output, expectations), 2);
        double result = matrix.matrixSum(square) / (er * ec);
        return Math.sqrt(result);
    }

    /**
     * L1损失函数
     *
     * @param expectations 期望值（标量）
     * @param output       输出值（标量）
     * @return L2损失函数的解（标量）
     */
    @Override
    public double l1LossFunction(double expectations, double output) {
        return Math.abs(output - expectations);
    }

    /**
     * L1损失函数
     *
     * @param expectations 期望值（向量）
     * @param output       输出值（向量）
     * @return L2损失函数的解（标量）
     */
    @Override
    public double l1LossFunction(double[] expectations, double[] output) {
        int er = expectations.length;
        double[] abs = matrix.abs(matrix.sub(output, expectations));
        return matrix.sum(abs) / er;
    }

    /**
     * L1损失函数
     *
     * @param expectations 期望值（矩阵）
     * @param output       输出值（矩阵）
     * @return L2损失函数的解（标量）
     */
    @Override
    public double l1LossFunction(double[][] expectations, double[][] output) {
        int er = expectations.length;
        int ec = expectations[0].length;
        double[][] abs = matrix.abs(matrix.sub(output, expectations));
        return matrix.sum(abs) / (er * ec);
    }

    /**
     * Smooth L1损失函数
     *
     * @param expectations 期望值（标量）
     * @param output       输出值（标量）
     * @return Smooth L1损失函数的解（标量）
     */
    @Override
    public double smoothL1LossFunction(double expectations, double output) {
        double conditions = Math.abs(output - expectations);
        if (conditions < 1) {
            return Math.pow(conditions, 2) * 0.5;
        } else {
            return conditions - 0.5;
        }
    }

    /**
     * Smooth L1损失函数
     *
     * @param expectations 期望值（向量）
     * @param output       输出值（向量）
     * @return Smooth L1损失函数的解（标量）
     */
    @Override
    public double smoothL1LossFunction(double[] expectations, double[] output) {
        int er = expectations.length;
        double[] conditions = matrix.abs(matrix.sub(output, expectations));
        double result = 0;
        for (int i = 0; i < er; i++) {
            if (conditions[i] < 1) {
                result += Math.pow(conditions[i], 2) * 0.5;
            } else {
                result += conditions[i] - 0.5;
            }
        }
        return result;
    }

    /**
     * Smooth L1损失函数
     *
     * @param expectations 期望值（矩阵）
     * @param output       输出值（矩阵）
     * @return Smooth L1损失函数的解（标量）
     */
    @Override
    public double smoothL1LossFunction(double[][] expectations, double[][] output) {
        int er = expectations.length;
        int ec = expectations[0].length;
        double[][] conditions = matrix.abs(matrix.sub(output, expectations));
        double result = 0;
        for (int i = 0; i < er; i++) {
            for (int j = 0; j < ec; j++) {
                if (conditions[i][j] < 1) {
                    result += Math.pow(conditions[i][j], 2) * 0.5;
                } else {
                    result += conditions[i][j] - 0.5;
                }
            }
        }
        return result;
    }

    /**
     * huber损失函数
     *
     * @param expectations 期望值（标量）
     * @param output       输出值（标量）
     * @param delta        delta
     * @return huber损失函数的解（标量）
     */
    @Override
    public double huBerLossFunction(double expectations, double output, double delta) {
        double conditions = Math.abs(output - expectations);
        if (conditions < 1) {
            return Math.pow(conditions, 2) * 0.5;
        } else {
            return delta * conditions - 0.5 * Math.pow(delta, 2);
        }
    }

    /**
     * huber损失函数
     *
     * @param expectations 期望值（向量）
     * @param output       输出值（向量）
     * @param delta        delta
     * @return huber损失函数的解（标量）
     */
    @Override
    public double huBerLossFunction(double[] expectations, double[] output, double delta) {
        int er = expectations.length;
        double[] conditions = matrix.abs(matrix.sub(output, expectations));
        double result = 0;
        for (int i = 0; i < er; i++) {
            if (conditions[i] < 1) {
                result += Math.pow(conditions[i], 2) * 0.5;
            } else {
                result += delta * conditions[i] - 0.5 * Math.pow(delta, 2);
            }
        }
        return result;
    }

    /**
     * huber损失函数
     *
     * @param expectations 期望值（矩阵）
     * @param output       输出值（矩阵）
     * @param delta        delta
     * @return huber损失函数的解（标量）
     */
    @Override
    public double huBerLossFunction(double[][] expectations, double[][] output, double delta) {
        huBerLossFunctionDelta = delta;
        int er = expectations.length;
        int ec = expectations[0].length;
        double[][] conditions = matrix.abs(matrix.sub(output, expectations));
        double result = 0;
        for (int i = 0; i < er; i++) {
            for (int j = 0; j < ec; j++) {
                if (conditions[i][j] < 1) {
                    result += Math.pow(conditions[i][j], 2) * 0.5;
                } else {
                    result += conditions[i][j] - 0.5 * Math.pow(delta, 2);
                }
            }
        }
        return result;
    }

    /**
     * KL散度函数（相对熵）
     *
     * @param expectations 期望值（标量）
     * @param output       输出值（标量）
     * @return KL散度函数（相对熵）的解（标量）
     */
    @Override
    public double kullbackLeiblerDivergenceFunction(double expectations, double output) {
        // 改用自然对数
        double left = expectations * Math.log(expectations);
        double right = expectations * Math.log(output);
        return left - right;
    }

    /**
     * KL散度函数（相对熵）
     *
     * @param expectations 期望值（向量）
     * @param output       输出值（向量）
     * @return KL散度函数（相对熵）的解（标量）
     */
    @Override
    public double kullbackLeiblerDivergenceFunction(double[] expectations, double[] output) {
        double[] leftResult = matrix.elementProduct(expectations, matrix.ln(expectations));
        double[] rightResult = matrix.elementProduct(expectations, matrix.ln(output));
        double[] KL = matrix.sub(leftResult, rightResult);
        return matrix.sum(KL);
    }

    /**
     * KL散度函数（相对熵）
     *
     * @param expectations 期望值（矩阵）
     * @param output       输出值（矩阵）
     * @return KL散度函数（相对熵）的解（标量）
     */
    @Override
    public double kullbackLeiblerDivergenceFunction(double[][] expectations, double[][] output) {
        double[][] leftResult = matrix.elementProduct(expectations, matrix.ln(expectations));
        double[][] rightResult = matrix.elementProduct(expectations, matrix.ln(output));
        double[][] KL = matrix.sub(leftResult, rightResult);
        return matrix.sum(KL);
    }

    /**
     * 交叉熵损失
     *
     * @param expectations 期望值（标量）
     * @param output       输出值（标量）
     * @return 交叉熵损失的解（标量）
     */
    @Override
    public double crossEntropyLossFunction(double expectations, double output) {
        return -1 * expectations * Math.log(output);
    }

    /**
     * 交叉熵损失
     *
     * @param expectations 期望值（向量）
     * @param output       输出值（向量）
     * @return 交叉熵损失的解（标量）
     */
    @Override
    public double crossEntropyLossFunction(double[] expectations, double[] output) {
        double[] log = matrix.elementProduct(matrix.multi(expectations,-1), matrix.ln(output));
        return matrix.sum(log);
    }

    /**
     * 交叉熵损失
     *
     * @param expectations 期望值（矩阵）
     * @param output       输出值（矩阵）
     * @return 交叉熵损失的解（标量）
     */
    @Override
    public double crossEntropyLossFunction(double[][] expectations, double[][] output) {
        double[][] log = matrix.elementProduct(matrix.multi(expectations,-1), matrix.ln(output));
        return matrix.sum(log);
    }

    /**
     * softmax损失函数
     *
     * @param expectations 期望值（标量）
     * @param output       输出值（标量）
     * @return softmax损失函数的解（标量）
     */
    @Override
    public double softmaxLossFunction(double expectations, double output) {
        return 0;
    }

    /**
     * softmax损失函数
     *
     * @param expectations 期望值（向量）
     * @param output       输出值（向量）
     * @return softmax损失函数的解（标量）
     */
    @Override
    public double softmaxLossFunction(double[] expectations, double[] output) {
        double[] softmaxOutput = activateable.softmax(output);
        return crossEntropyLossFunction(expectations, softmaxOutput);
    }

    /**
     * softmax损失函数
     *
     * @param expectations 期望值（矩阵）
     * @param output       输出值（矩阵）
     * @return softmax损失函数的解（标量）
     */
    @Override
    public double softmaxLossFunction(double[][] expectations, double[][] output) {
        double[][] softmaxOutput = activateable.softmax(output);
        return crossEntropyLossFunction(expectations, softmaxOutput);
    }

    /**
     * FocalLoss (局灶性损失函数)
     *
     * @param expectations 期望值（标量）
     * @param output       输出值（标量）
     * @param alpha        解决正负样本不均衡的 alpha 值
     * @param beta         解决难样本 beta 值
     * @return FocalLoss (局灶性损失函数)的解（标量）
     */
    @Override
    public double focalLossFunction(double expectations, double output, double alpha, double beta) {
        focalLossFunctionAlpha = alpha;
        focalLossFunctionBeta  = beta;
        double pt;
        if (expectations == 1) {
            pt = output;
        } else {
            pt = 1 - output;
        }
        double difficultSamples = Math.pow(1 - pt, beta);
        double log = Math.log(pt);
        return -1 * alpha * difficultSamples * log;
    }

    /**
     * FocalLoss (局灶性损失函数)
     *
     * @param expectations 期望值（向量）
     * @param output       输出值（向量）
     * @param alpha        解决正负样本不均衡的 alpha 值
     * @param beta         解决难样本 beta 值
     * @return FocalLoss (局灶性损失函数)的解（标量）
     */
    @Override
    public double focalLossFunction(double[] expectations, double[] output, double alpha, double beta) {

        int er = expectations.length;
        double[] pt = new double[er];
        for (int i = 0; i < er; i++) {
            if (expectations[i] == 1) {
                pt[i] = output[i];
            } else {
                pt[i] = 1 - output[i];
            }
        }
        double[] difficultSamples = matrix.pow(matrix.sub(1, pt), beta);
        double[] log = matrix.ln(pt);
        double[] fl = matrix.elementProduct(difficultSamples, log);
        double[] result = matrix.elementProduct(matrix.customNumber(-1 * alpha, er), fl);
        return matrix.sum(result);
    }

    /**
     * FocalLoss (局灶性损失函数)
     *
     * @param expectations 期望值（矩阵）
     * @param output       输出值（矩阵）
     * @param alpha        解决正负样本不均衡的 alpha 值
     * @param beta         解决难样本 beta 值
     * @return FocalLoss (局灶性损失函数)的解（标量）
     */
    @Override
    public double focalLossFunction(double[][] expectations, double[][] output, double alpha, double beta) {
        int er = expectations.length;
        int ec = expectations[0].length;
        double[][] pt = new double[er][ec];
        for (int i = 0; i < er; i++) {
            for (int j = 0; j < ec; j++) {
                if (expectations[i][j] == 1) {
                    pt[i][j] = output[i][j];
                } else {
                    pt[i][j] = 1 - output[i][j];
                }
            }

        }
        double[][] difficultSamples = matrix.pow(matrix.sub(matrix.customNumber(1, er, ec), pt), beta);
        double[][] log = matrix.ln(pt);
        double[][] fl = matrix.elementProduct(difficultSamples, log);
        double[][] result = matrix.elementProduct(matrix.customNumber(-1 * alpha, er, ec), fl);
        return matrix.sum(result);
    }

    /**
     * 均方误差损失函数（MSE）    求导
     *
     * @param expectations 期望值（标量）
     * @param output       输出值（标量）
     * @return 均方误差损失函数（MSE）的解（标量）
     */
    @Override
    public double derivationMeanSquareErrorLossFunction(double expectations, double output) {
        return 2 * (output - expectations);
    }

    /**
     * 均方误差损失函数（MSE）    求导
     *
     * @param expectations 期望值（向量）
     * @param output       输出值（向量）
     * @return 均方误差损失函数（MSE）的解（向量）
     */
    @Override
    public double[] derivationMeanSquareErrorLossFunction(double[] expectations, double[] output) {
        int er = expectations.length;
        return matrix.elementProduct(matrix.customNumber(2, er), matrix.sub(output, expectations));
    }

    /**
     * 均方误差损失函数（MSE）    求导
     *
     * @param expectations 期望值（矩阵）
     * @param output       输出值（矩阵）
     * @return 均方误差损失函数（MSE）的解（矩阵）
     */
    @Override
    public double[][] derivationMeanSquareErrorLossFunction(double[][] expectations, double[][] output) {
        int er = expectations.length;
        int ec = expectations[0].length;
        return matrix.elementProduct(matrix.customNumber(2, er, ec), matrix.sub(output, expectations));
    }

    /**
     * L2损失函数   求导
     *
     * @param expectations 期望值（标量）
     * @param output       输出值（标量）
     * @return L2损失函数的解（标量）
     */
    @Override
    public double derivationL2LossFunction(double expectations, double output) {
        return 2 * output * (output - expectations);
    }

    /**
     * L2损失函数   求导
     *
     * @param expectations 期望值（向量）
     * @param output       输出值（向量）
     * @return L2损失函数的解（向量）
     */
    @Override
    public double[] derivationL2LossFunction(double[] expectations, double[] output) {
        double[] derivationActivation = activateable.derivationActivationSolve(layer.getzLayer(), layer.getActivationType());
        double[] temp = matrix.elementProduct(derivationActivation, matrix.sub(output, expectations));
        return matrix.multi(temp, 2);
    }

    /**
     * L2损失函数   求导
     *
     * @param expectations 期望值（矩阵）
     * @param output       输出值（矩阵）
     * @return L2损失函数的解（矩阵）
     */
    @Override
    public double[][] derivationL2LossFunction(double[][] expectations, double[][] output) {
        double[] derivationActivation = activateable.derivationActivationSolve(layer.getzLayer(), layer.getActivationType());
        double[][] derivationActivationMatrix = matrix.vectorToRowMatrix(derivationActivation);
        double[][] temp = matrix.elementProduct(derivationActivationMatrix, matrix.sub(output, expectations));
        return matrix.multi(temp, 2);
    }

    /**
     * L1损失函数   求导
     *
     * @param expectations 期望值（标量）
     * @param output       输出值（标量）
     * @return L2损失函数的解（标量）
     */
    @Override
    public double derivationL1LossFunction(double expectations, double output) {
        return output - expectations;
    }

    /**
     * L1损失函数   求导
     *
     * @param expectations 期望值（向量）
     * @param output       输出值（向量）
     * @return L2损失函数的解（向量）
     */
    @Override
    public double[] derivationL1LossFunction(double[] expectations, double[] output) {
        return matrix.sub(output, expectations);
    }

    /**
     * L1损失函数   求导
     *
     * @param expectations 期望值（矩阵）
     * @param output       输出值（矩阵）
     * @return L2损失函数的解（矩阵）
     */
    @Override
    public double[][] derivationL1LossFunction(double[][] expectations, double[][] output) {
        return matrix.sub(output, expectations);
    }

    /**
     * Smooth L1损失函数    求导
     *
     * @param expectations 期望值（标量）
     * @param output       输出值（标量）
     * @return Smooth L1损失函数的解（标量）
     */
    @Override
    public double derivationSmoothL1LossFunction(double expectations, double output) {
        double result = 0;
        if (!(Math.abs(output) < 1)) {
            if (output < 0) {
                result = -1;
            } else if (output > 1) {
                result = 1;
            }
        } else {
            result = output - expectations;
        }
        return result;
    }

    /**
     * Smooth L1损失函数    求导
     *
     * @param expectations 期望值（向量）
     * @param output       输出值（向量）
     * @return Smooth L1损失函数的解（向量）
     */
    @Override
    public double[] derivationSmoothL1LossFunction(double[] expectations, double[] output) {
        int or = output.length;
        double[] result = new double[or];
        for (int i = 0; i < or; i++) {
            if (!(Math.abs(output[i]) < 1)) {
                if (output[i] < 0) {
                    result[i] = -1;
                } else if (output[i] > 1) {
                    result[i] = 1;
                }
            } else {
                result[i] = output[i] - expectations[i];
            }
        }
        return result;
    }

    /**
     * Smooth L1损失函数    求导
     *
     * @param expectations 期望值（矩阵）
     * @param output       输出值（矩阵）
     * @return Smooth L1损失函数的解（矩阵）
     */
    @Override
    public double[][] derivationSmoothL1LossFunction(double[][] expectations, double[][] output) {
        int or = output.length;
        int oc = output[0].length;
        double[][] result = new double[or][oc];
        for (int i = 0; i < or; i++) {
            for (int j = 0; j < oc; j++) {
                if (!(Math.abs(output[i][j]) < 1)) {
                    if (output[i][j] < 0) {
                        result[i][j] = -1;
                    } else if (output[i][j] > 1) {
                        result[i][j] = 1;
                    }
                } else {
                    result[i][j] = output[i][j] - expectations[i][j];
                }
            }
        }
        return result;
    }

    /**
     * huber损失函数    求导
     *
     * @param expectations 期望值（标量）
     * @param output       输出值（标量）
     * @return huber损失函数的解（标量）
     */
    @Override
    public double derivationHuBerLossFunction(double expectations, double output) {
        return 0;
    }

    /**
     * huber损失函数    求导
     *
     * @param expectations 期望值（向量）
     * @param output       输出值（向量）
     * @return huber损失函数的解（向量）
     */
    @Override
    public double[] derivationHuBerLossFunction(double[] expectations, double[] output) {
        return new double[0];
    }

    /**
     * huber损失函数    求导
     *
     * @param expectations 期望值（矩阵）
     * @param output       输出值（矩阵）
     * @return huber损失函数的解（矩阵）
     */
    @Override
    public double[][] derivationHuBerLossFunction(double[][] expectations, double[][] output) {
        int er = expectations.length;
        int ec = expectations[0].length;
        double[][] deltaMatrix = matrix.customNumber(huBerLossFunctionDelta, er, ec);
        double[][] diff = matrix.sub(output, expectations);
        double[][] conditions = matrix.abs(diff);
        double[][] grad = new double[er][ec];
        for (int i = 0; i < er; i++) {
            for (int j = 0; j < ec; j++) {
                grad[i][j] = (conditions[i][j] <= huBerLossFunctionDelta) ? diff[i][j] : huBerLossFunctionDelta * Math.signum(diff[i][j]);
            }
        }
        return grad;
    }

    /**
     * KL散度函数（相对熵）  求导
     *
     * @param expectations 期望值（标量）
     * @param output       输出值（标量）
     * @return KL散度函数（相对熵）的解（标量）
     */
    @Override
    public double derivationKullbackLeiblerDivergenceFunction(double expectations, double output) {
        return -1 * expectations / output;
    }

    /**
     * KL散度函数（相对熵）  求导
     *
     * @param expectations 期望值（向量）
     * @param output       输出值（向量）
     * @return KL散度函数（相对熵）的解（向量）
     */
    @Override
    public double[] derivationKullbackLeiblerDivergenceFunction(double[] expectations, double[] output) {
        int or = output.length;
        double[] result = new double[or];
        for (int i = 0; i < or; i++) {
            result[i] = (-1 * expectations[i] / output[i]) / or;
        }
        return result;
    }

    /**
     * KL散度函数（相对熵）  求导
     *
     * @param expectations 期望值（矩阵）
     * @param output       输出值（矩阵）
     * @return KL散度函数（相对熵）的解（矩阵）
     */
    @Override
    public double[][] derivationKullbackLeiblerDivergenceFunction(double[][] expectations, double[][] output) {
        int or = output.length;
        int oc = output[0].length;
        double[][] result = new double[or][oc];
        for (int i = 0; i < or; i++) {
            for (int j = 0; j < oc; j++) {
                result[i][j] = (-1 * expectations[i][j] / output[i][j]) / oc;
            }
        }
        return result;
    }

    /**
     * 交叉熵损失    求导
     *
     * @param expectations 期望值（标量）
     * @param output       输出值（标量）
     * @return 交叉熵损失的解（标量）
     */
    @Override
    public double derivationCrossEntropyLossFunction(double expectations, double output) {
        return -1 * expectations * (1 / output);
    }

    /**
     * 交叉熵损失    求导
     *
     * @param expectations 期望值（向量）
     * @param output       输出值（向量）
     * @return 交叉熵损失的解（向量）
     */
    @Override
    public double[] derivationCrossEntropyLossFunction(double[] expectations, double[] output) {
        return matrix.sub(output, expectations); // 正确导数公式
    }

    /**
     * 交叉熵损失    求导
     *
     * @param expectations 期望值（矩阵）
     * @param output       输出值（矩阵）
     * @return 交叉熵损失的解（矩阵）
     */
    @Override
    public double[][] derivationCrossEntropyLossFunction(double[][] expectations, double[][] output) {
        int or = output.length;
        int oc = output[0].length;
        double[][] result = new double[or][oc];
        for (int i = 0; i < or; i++) {
            for (int j = 0; j < oc; j++) {
                result[i][j] = (-1 * expectations[i][j] * (1 / output[i][j])) / oc;
            }
        }
        return result;
    }

    /**
     * softmax损失函数  求导
     *
     * @param expectations 期望值（标量）
     * @param output       输出值（标量）
     * @return softmax损失函数的解（标量）
     */
    @Override
    public double derivationSoftmaxLossFunction(double expectations, double output) {
        return output - expectations;
    }

    /**
     * softmax损失函数  求导
     *
     * @param expectations 期望值（向量）
     * @param output       输出值（向量）
     * @return softmax损失函数的解（向量）
     */
    @Override
    public double[] derivationSoftmaxLossFunction(double[] expectations, double[] output) {
        double[] softmaxOutput = activateable.softmax(output);
        return matrix.sub(output, expectations);
    }

    /**
     * softmax损失函数  求导
     *
     * @param expectations 期望值（矩阵）
     * @param output       输出值（矩阵）
     * @return softmax损失函数的解（矩阵）
     */
    @Override
    public double[][] derivationSoftmaxLossFunction(double[][] expectations, double[][] output) {
        double[][] softmaxOutput = activateable.softmax(output);
        return matrix.sub(output, expectations);
    }

    /**
     * FocalLoss (局灶性损失函数)  求导
     *
     * @param expectations 期望值（标量）
     * @param output       输出值（标量）
     * @return FocalLoss (局灶性损失函数)的解（标量）
     */
    @Override
    public double derivationFocalLossFunction(double expectations, double output) {
        double pt = (expectations == 1) ? output : 1 - output;
        double grad = -focalLossFunctionAlpha * focalLossFunctionBeta * Math.pow(1 - pt, focalLossFunctionBeta - 1) * (Math.log(pt) + (1 - pt)/pt);
        return (expectations == 1) ? grad : -grad;
    }

    /**
     * FocalLoss (局灶性损失函数)  求导
     *
     * @param expectations 期望值（向量）
     * @param output       输出值（向量）
     * @return FocalLoss (局灶性损失函数)的解（向量）
     */
    @Override
    public double[] derivationFocalLossFunction(double[] expectations, double[] output) {
        return new double[0];
    }

    /**
     * FocalLoss (局灶性损失函数)  求导
     *
     * @param expectations 期望值（矩阵）
     * @param output       输出值（矩阵）
     * @return FocalLoss (局灶性损失函数)的解（矩阵）
     */
    @Override
    public double[][] derivationFocalLossFunction(double[][] expectations, double[][] output) {
        return new double[0][];
    }
}
